using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Windows;
using Boggle.Net.Model;
using Caliburn.Micro;

namespace Boggle.Net.ViewModels
{
    public sealed class TrayViewModel : PropertyChangedBase
    {
        private readonly Selection<TrayCell> _selection = new Selection<TrayCell>();

        private readonly Tray _tray;
        private readonly TrayCell[] _cellList;

        private AcceptablePlay _tracedPlay;
        private bool _isEnabled = true;

        public TrayViewModel(Tray tray)
        {
            Contract.Requires<ArgumentNullException>(tray != null);

            _tray = tray;
            _cellList = _tray.AllLocations.Select(location => new TrayCell(_tray, location) { Selection = Selection }).ToArray();

            Selection.Changed += delegate
                                 {
                                     NotifyOfPropertyChange(() => SelectedWord);
                                     if (!Selection.IsEmpty) TracedPlay = null;
                                 };
        }

        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                if (value == IsEnabled) return;

                _isEnabled = value;
                NotifyOfPropertyChange(() => IsEnabled);
            }
        }

        public IEnumerable<TrayCell> CellList
        {
            get { return _cellList; }
        }

        public Selection<TrayCell> Selection
        {
            get { return _selection; }
        }

        public AcceptablePlay TracedPlay
        {
            get { return _tracedPlay; }
            set
            {
                if (value == TracedPlay) return;

                _tracedPlay = value;
                NotifyOfPropertyChange(() => TracedPlay);
            }
        }

        public IEnumerable<Tray.Location> SelectedPath
        {
            get { return Selection.Select(cell => cell.Location).ToArray(); }
        }

        public string SelectedWord
        {
            get { return String.Concat(Selection.Select(cell => _tray.LettersAt(cell.Location))); }
        }

        public void CopyToClipboard()
        {
            var text = _tray.ToRows();

            // Workaround for: OpenClipboard Failed (Exception from HRESULT: 0x800401D0 (CLIPBRD_E_CANT_OPEN))

            const int attempts = 10;

            for (var i = 0; i < attempts; ++i)
            {
                try
                {
                    Clipboard.SetText(text);
                    break;
                }
                catch (Exception exception)
                {
                    System.Diagnostics.Trace.WriteLine(exception);
                }

                System.Threading.Thread.Sleep(10);
            }
        }
    }
}